package cmd

import (
	"bytes"
	"fmt"
	"os"
	"regexp"
	"sort"
	"strconv"
	"strings"
	"text/template"

	"github.com/spf13/cobra"
)

// 定义正则表达式
var (
	// 匹配所有类型的提交，支持中英文字符和标点
	commitRegex = regexp.MustCompile(`^(?:(\w+)(?:\(([\p{Han}\p{L}\d\s_/.-]+)\))?\s*:\s*)?(.+)`)
	// 匹配版本号格式，支持大写V和无V的情况
	versionRegex = regexp.MustCompile(`[vV]?\d+\.\d+\.\d+`)
)

// 在文件开头添加版本常量
const Version = "v0.1.0"

// rootCmd 定义主命令
var rootCmd = &cobra.Command{
	Use:   "gitlog",
	Short: "Git commit message 日志整合工具 | Git commit message integration tool",
	Long: `一个用于整合Git提交信息的命令行工具。
可以帮助你更好地组织和查看项目的提交历史。

A command-line tool for integrating Git commit messages.
It helps you better organize and view project commit history.`,
	Run: runCommand,
}

// runCommand 处理命令执行
func runCommand(cmd *cobra.Command, args []string) {
	// 检查版本标志
	if version, _ := cmd.Flags().GetBool("version"); version {
		fmt.Printf("gitlog version %s\n", Version)
		return
	}

	limit, _ := cmd.Flags().GetInt("limit")
	showDetail, _ := cmd.Flags().GetBool("detail")
	reverse, _ := cmd.Flags().GetBool("reverse")
	self, _ := cmd.Flags().GetBool("self")
	author, _ := cmd.Flags().GetString("author")
	branch, _ := cmd.Flags().GetString("branch")

	// 获取当前用户的 git 配置邮箱
	if self {
		email, err := getGitUserEmail()
		if err == nil {
			author = email
		}
	}

	listCommits(limit, showDetail, reverse, author, branch)
}

// init 初始化命令行参数
func init() {
	cobra.AddTemplateFunc("zh", func(s string) string {
		return "显示帮助信息"
	})

	rootCmd.SetHelpTemplate(`{{with (or .Long .Short)}}{{. | trimTrailingWhitespaces}}

{{end}}{{if or .Runnable .HasSubCommands}}{{.UsageString}}{{end}}`)

	// 设置命令行参数
	flags := rootCmd.Flags()
	flags.IntP("limit", "l", 50, formatHelp("要显示的提交数量", "Number of commits to show"))
	flags.BoolP("detail", "d", false, formatHelp("显示详细信息", "Show detailed information"))
	flags.BoolP("reverse", "r", false, formatHelp("倒序排列", "Reverse order"))
	flags.BoolP("self", "m", false, formatHelp("仅显示自己的提交", "Show only your commits"))
	flags.StringP("author", "a", "", formatHelp("指定提交作者", "Specify commit author"))
	flags.StringP("branch", "b", "", formatHelp("指定分支", "Specify branch"))

	// 修改 help 标志的描述
	rootCmd.PersistentFlags().BoolP("help", "h", false, formatHelp("显示帮助信息", "Show help message"))

	// 添加版本标志
	rootCmd.Flags().BoolP("version", "v", false, formatHelp("显示版本信息", "Show version information"))
}

// parseCommits 解析提交信息
func parseCommits(log string) map[string]*CommitInfo {
	commits := strings.Split(log, "==COMMIT_END==")
	commitMap := make(map[string]*CommitInfo)
	config := loadConfig()

	for _, commit := range commits {
		commit = strings.TrimSpace(commit)
		if commit == "" {
			continue
		}

		lines := strings.Split(commit, "\n")
		if len(lines) < 2 { // 至少需要时间戳和提交信息
			continue
		}

		// 解析时间戳
		timestamp, err := strconv.ParseInt(strings.TrimSpace(lines[0]), 10, 64)
		if err != nil {
			continue
		}

		// 移除时间戳行，处理实际提交信息
		lines = lines[1:]
		firstLine := convertPunctuation(lines[0])
		
		// 跳过 Merge 提交
		if strings.HasPrefix(firstLine, "Merge") {
			continue
		}

		// 提取提交类型和原始消息
		matches := commitRegex.FindStringSubmatch(firstLine)
		commitType := ""
		scope := ""
		title := firstLine

		if len(matches) > 3 {
			commitType = matches[1]
			scope = matches[2]
			title = matches[3]
		}

		// 检查是否是需要包含的类型
		typeIncluded := false
		for _, t := range config.IncludeTypes {
			if (t == "" && commitType == "") || (t != "" && commitType == t) {
				typeIncluded = true
				break
			}
		}

		if !typeIncluded {
			continue
		}

		// 提取版本号
		version := ""
		versionMatch := versionRegex.FindString(title)
		if versionMatch != "" {
			version = normalizeVersion(versionMatch)
			title = strings.TrimSpace(strings.Replace(title, versionMatch, "", 1))
		}

		// 获取描述
		var description []string
		for _, line := range lines[1:] {
			line = strings.TrimSpace(line)
			if line != "" {
				line = convertPunctuation(line)
				line = cleanDetailPrefix(line)
				description = append(description, line)
			}
		}

		// 准备版本号列表
		versions := []string{}
		if version != "" {
			versions = append(versions, version)
		}

		key := fmt.Sprintf("%s:%s", scope, title)
		if existing, ok := commitMap[key]; ok {
			if version != "" && !contains(existing.Versions, version) {
				// 添加新版本及其描述
				existing.Versions = append(existing.Versions, version)
				existing.Versions = sortVersions(existing.Versions)
				
				existing.VersionDescs = append(existing.VersionDescs, VersionDesc{
					Version:     version,
					Description: description,
				})
				
				// 按版本号排序 VersionDescs
				sort.Slice(existing.VersionDescs, func(i, j int) bool {
					return compareVersions(existing.VersionDescs[i].Version, existing.VersionDescs[j].Version)
				})
				
				// 重建 Description 列表
				existing.Description = []string{}
				for _, vd := range existing.VersionDescs {
					existing.Description = append(existing.Description, vd.Description...)
				}
			} else if version != "" {
				// 如果版本已存在，更新或添加描述
				for i, vd := range existing.VersionDescs {
					if vd.Version == version {
						// 添加新的描述
						for _, desc := range description {
							if !contains(vd.Description, desc) {
								existing.VersionDescs[i].Description = append(existing.VersionDescs[i].Description, desc)
							}
						}
						break
					}
				}
				// 重建 Description 列表
				existing.Description = []string{}
				for _, vd := range existing.VersionDescs {
					existing.Description = append(existing.Description, vd.Description...)
				}
			}
			
			// 更新时间戳为最新的
			if timestamp > existing.Timestamp {
				existing.Timestamp = timestamp
			}
		} else {
			// 创建新的提交信息
			versionDescs := []VersionDesc{}
			if version != "" {
				versionDescs = append(versionDescs, VersionDesc{
					Version:     version,
					Description: description,
				})
			}
			
			commitMap[key] = &CommitInfo{
				Scope:         scope,
				Title:         title,
				OriginalTitle: firstLine,
				Versions:      versions,
				Description:   description,
				VersionDescs:  versionDescs,
				Timestamp:     timestamp,
			}
		}
	}

	return commitMap
}

// listCommits 显示提交记录
func listCommits(limit int, showDetail bool, reverse bool, author string, branch string) {
	log, err := getGitLog(limit, author, branch)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error: %v\n", err)
		os.Exit(1)
	}

	commitMap := parseCommits(log)

	var commits []*CommitInfo
	for _, commit := range commitMap {
		commits = append(commits, commit)
	}

	// 根据时间戳排序
	sort.Slice(commits, func(i, j int) bool {
		if reverse {
			return commits[i].Timestamp < commits[j].Timestamp
		}
		return commits[i].Timestamp > commits[j].Timestamp
	})

	config := loadConfig()
	goTemplate := convertFormat(config.Format)
	tmpl, err := template.New("commit").Parse(goTemplate)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error parsing format template: %v\n", err)
		os.Exit(1)
	}

	for _, commit := range commits {
		data := TemplateData{
			Type:               commit.Scope,
			Scope:              commit.Scope,
			Title:              commit.Title,
			OriginalTitle:      commit.OriginalTitle,
			Versions:           len(commit.Versions) > 0,
			HasMultipleVersions: len(commit.Versions) > 1,
		}

		if len(commit.Versions) > 0 {
			data.FirstVersion = commit.Versions[0]
			data.LastVersion = commit.Versions[len(commit.Versions)-1]
		}

		var buf bytes.Buffer
		if err := tmpl.Execute(&buf, data); err != nil {
			fmt.Fprintf(os.Stderr, "Error executing template: %v\n", err)
			continue
		}

		fmt.Println(buf.String())

		// 显示详细信息
		if showDetail && len(commit.Description) > 0 {
			detailGoTemplate := convertFormat(config.DetailFormat)
			detailTmpl, err := template.New("detail").Parse(detailGoTemplate)
			if err != nil {
				fmt.Fprintf(os.Stderr, "Error parsing detail format template: %v\n", err)
				continue
			}

			for i, desc := range commit.Description {
				data := DetailData{
					Detail: desc,
					Order:  i + 1,
				}

				var buf bytes.Buffer
				if err := detailTmpl.Execute(&buf, data); err != nil {
					fmt.Fprintf(os.Stderr, "Error executing detail template: %v\n", err)
					continue
				}

				fmt.Printf("    %s\n", buf.String())
			}
			fmt.Println()
		}
	}
}

// Execute 执行根命令
func Execute() {
	if err := rootCmd.Execute(); err != nil {
		os.Exit(1)
	}
}


